﻿// <copyright file="DiscountType.cs" company="NorthCoast NERO">
//     NorthCoast NERO. All rights reserved.
// </copyright>
// <author>Eric Kociecki</author>
namespace NcnPlayerCheckIn
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// An object that can represent a specific type of discount.
    /// </summary>
    public class DiscountType
    {
        /// <summary>
        /// Gets or sets the human-readable name of the discount.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the dollar value of the discount.
        /// </summary>
        public double Value { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether or not this discount can stack with other discounts.  A value of false means that it cannot stack with any other discounts that also have IsStackable set to false.  A value ot true can stack with any other DiscountType regardless of the value of the other object's IsStackable property.
        /// </summary>
        public bool IsStackable { get; set; }

        /// <summary>
        /// Gets or sets an ID for the DiscountType.  This ID should be unique among all DiscountType objects.
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// Determines whether the two DiscountType objects are equal.
        /// </summary>
        /// <param name="operandA">The first DiscountType object to compare.</param>
        /// <param name="operandB">The second DiscountType object to compare.</param>
        /// <returns>A value indicating whether the specified DiscountType objects are equal.</returns>
        public static bool operator ==(DiscountType operandA, DiscountType operandB)
        {
            if (ReferenceEquals(operandA, operandB))
            {
                return true;
            }

            if (((object)operandA == null) || ((object)operandB == null))
            {
                return false;
            }

            return (operandA.Name == operandB.Name) && (operandA.Value == operandB.Value) && (operandA.IsStackable == operandB.IsStackable);
        }

        /// <summary>
        /// Determines whether the two DiscountType objects are not equal.
        /// </summary>
        /// <param name="operandA">The first DiscountType object to compare.</param>
        /// <param name="operandB">The second DiscountType object to compare.</param>
        /// <returns>A value indicating whether the specified DiscountType objects are not equal.</returns>
        public static bool operator !=(DiscountType operandA, DiscountType operandB)
        {
            return !(operandA == operandB);
        }

        /// <summary>
        /// Determines whether the two specified System.Objects are equal.
        /// </summary>
        /// <param name="operandA">The first System.Object to compare.</param>
        /// <param name="operandB">The second System.Object to compare.</param>
        /// <returns>A value indicating whether the two specified System.Objects are equal.</returns>
        public new static bool Equals(object operandA, object operandB)
        {
            if (ReferenceEquals(operandA, operandB))
            {
                return true;
            }

            if (((object)operandA == null) || ((object)operandB == null))
            {
                return false;
            }

            DiscountType discountA = operandA as DiscountType;
            if ((object)discountA == null)
            {
                return false;
            }

            DiscountType discountB = operandB as DiscountType;
            if ((object)discountB == null)
            {
                return false;
            }

            return (discountA.Name == discountB.Name) && (discountA.Value == discountB.Value) && (discountA.IsStackable == discountB.IsStackable);
        }

        /// <summary>
        /// Determines whether the specified System.Object is equal to the current DiscountType object.
        /// </summary>
        /// <param name="obj">The System.Object to compare to the current DiscountType object.</param>
        /// <returns>A value indicating whether the specified System.Object is equal to the current DiscountType object.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            DiscountType dt = obj as DiscountType;
            if ((object)dt == null)
            {
                return false;
            }

            return (this.Name == dt.Name) && (this.Value == dt.Value) && (this.IsStackable == dt.IsStackable);
        }
        
        /// <summary>
        /// Serves as a hash function for DiscountType.
        /// </summary>
        /// <returns>A hash value that is guaranteed to be the same for equal DiscountType objects.</returns>
        public override int GetHashCode()
        {
            int hashResult = 0;

            // hash Name
            foreach (char c in this.Name)
            {
                hashResult += Convert.ToInt32(c);
            }

            // hash Value
            hashResult *= (int)this.Value + 1;

            // hash IsStackable
            hashResult += this.IsStackable ? 111 : 0;

            return hashResult;
        }

        /// <summary>
        /// Converts this DiscountType into a string of the form "Name ($X)".  The value amount is not included if equal to zero.
        /// </summary>
        /// <returns>A string representation of the DiscountType.</returns>
        public override string ToString()
        {
            return string.Format(CultureInfo.CurrentCulture, this.Value == 0 ? "{0}" : "{0} (-${1})", this.Name, this.Value);
        }
    }
}
